﻿using Vboot.Core.Module.Sys;
using DbType = SqlSugar.DbType;

namespace Vboot.Core.Module.Bpm;

public class BpmProcMainService : BaseMainService<BpmProcMain>, ITransient
{
    //启动流程
    public async Task<Znode> Start(Zbpm zbpm)
    {

        //1 保存流程实例
        BpmProcMain bpmProcMain = new BpmProcMain(zbpm);
        bpmProcMain.crtim = DateTime.Now;
        bpmProcMain.avtag = true;
        bpmProcMain.state = "20";
        await repo.InsertAsync(bpmProcMain);

        //2 历史节点表保存开始节点
        await _nodeHistService.SaveStartNode(zbpm);

        //3 流程流转（收集流转过的节点，计算出下一个待审批节点）
        Znode draftNode = new Znode("N1");
        draftNode.facna = "起草节点";
        draftNode.facty = "draft";
        List<Znode> list = new List<Znode>();
        string xmlSql = "select t.chxml from bpm_proc_tmpl t where t.id=@tmpid";
        zbpm.chxml = repo.Context.Ado.SqlQuerySingle<string>(xmlSql, new {zbpm.tmpid});
        Znode nextNode = _hand.ProcFlow(zbpm, list, draftNode); //流转核心逻辑
        if (nextNode == null)
        {
            throw Oops.Oh("未找到下一个可流的流程节点");
        }
        await exmenTran(nextNode);//审批人转换

        //4.1 历史节点表保存起草节点
        draftNode.nodid = YitIdHelper.NextId() + "";
        await _nodeHistService.SaveDraftNode(zbpm, draftNode);
        //4.2 评审表保存起草节点的评审信息
        await _auditMainService.SaveDraftAudit(zbpm, draftNode);
        //4.3 历史节点表保存其他已流节点（条件分支等非审批节点）
        await _nodeHistService.SaveNodeList(zbpm, list);
        //4.4 当前节点表保存下一个待审批节点
        BpmNodeMain nodeMain = await _nodeMainService.SaveNode(zbpm, nextNode);
        nextNode.nodid = nodeMain.id;
        //4.5 历史节点表保存下一个待审批节点
        await _nodeHistService.SaveNode(nodeMain);

        //5.1 当前任务表创建待审节点的任务
        List<BpmTaskMain> mainTaskList = await _taskMainService.CreateTaskList(zbpm, nextNode);
        //5.2 历史任务表创建待审节点的任务
        await _taskHistService.CreateTaskList(mainTaskList);

        //6 发起待办
        await _todoService.SendTodos(zbpm, mainTaskList);
        return nextNode;
    }
    
    //通过流程
    public async Task<Znode> HandlerPass(Zbpm zbpm)
    {
        zbpm.haman = XuserUtil.getUserId();
        string sql = "select m.id as \"proid\",m.name as \"prona\" from bpm_proc_main m where m.id=@proid";
        dynamic map = repo.Context.Ado.SqlQuerySingle<dynamic>(sql, new {proid = zbpm.proid});
        zbpm.prona = "" + map.prona;

        BpmProcMain bpmProcMain = repo.Context.Queryable<BpmProcMain>()
            .Where(it => it.id == zbpm.proid).First();

        zbpm.opkey = "pass";
        zbpm.opinf = "通过";

        //1 评审表保存当前节点的评审信息
        await _auditMainService.SaveAudit(zbpm);
        if (!string.IsNullOrEmpty(zbpm.bacid))
        {
            await _paramService.Delete(zbpm.bacid);
        }

        //2.1 将历史任务变成已办
        BpmTaskHist histTask = await _taskHistService.FindOne(zbpm.tasid);
        histTask.haman = zbpm.haman;
        histTask.entim = DateTime.Now;
        histTask.state = "30";
        await _taskHistService.Update(histTask);
        //2.2 删除当前任务表记录
        await _taskMainService.Delete(zbpm.tasid);

        //3 流程流转
        Znode currNode = new Znode(zbpm.facno);
        currNode.nodid = zbpm.nodid;
        currNode.facno = zbpm.facno;
        currNode.facty = "review";
        if (!string.IsNullOrEmpty(zbpm.bacid))
        {
            currNode.tarno = zbpm.tarno;
            currNode.tarna = zbpm.tarna;
        }

        BpmNodeMain dbNode = await _nodeMainService.FindOne(currNode.nodid);
        if("1"==dbNode.flway){
            List<BpmTaskMain> bpmTaskMainList =await _taskMainService.FindAllByProidNotActive(zbpm.proid);
            if(bpmTaskMainList.Count>0){
                bpmTaskMainList[0].actag=true;
                await _taskMainService.Update(bpmTaskMainList[0]);
                await _taskHistService.CreateTask(bpmTaskMainList[0]);
                //7.1 删除之前的待办
                await _todoService.DoneTodos(zbpm);
                //7.2 发起新待办
                await _todoService.SendTodos(zbpm, bpmTaskMainList);
                return currNode;
            }
        }else if("2"==dbNode.flway){
            List<BpmTaskMain> bpmTaskMainList = await _taskMainService.FindAllByProid(zbpm.proid);
            foreach (var bpmTaskMain in bpmTaskMainList)
            {
              await  _taskMainService.Delete(bpmTaskMain.id);
              await  _taskHistService.Delete(bpmTaskMain.id);
            }
        }else if("3"==dbNode.flway){
            List<BpmTaskMain> bpmTaskMainList = await _taskMainService.FindAllByProid(zbpm.proid);
            if(bpmTaskMainList.Count>0){
                await _todoService.DoneTodo(zbpm);
                return currNode;
            }
        }
        
        List<Znode> list = new List<Znode>();
        string xmlSql = @"select t.chxml from bpm_proc_tmpl t inner join bpm_proc_main m on m.tmpid=t.id  where m.id=@proid";
        zbpm.chxml = repo.Context.Ado.SqlQuerySingle<string>(xmlSql, new {zbpm.proid});
        Znode nextNode = _hand.ProcFlow(zbpm, list, currNode); //流转核心逻辑
        if (nextNode == null)
        {
            throw Oops.Oh("未找到下一个可流的流程节点");
        }
        await exmenTran(nextNode);//审批人转换

        //4.1 将历史节点变成已办
        BpmNodeHist histNode = await _nodeHistService.FindOne(zbpm.nodid);
        histNode.entim = DateTime.Now;
        histNode.state = "30";
        histNode.tarno = currNode.tarno;
        histNode.tarna = currNode.tarna;
        await _nodeHistService.Update(histNode);
        currNode.facna = histNode.facna;
        //4.2 历史节点表保存已流节点
        await _nodeHistService.SaveNodeList(zbpm, list);
        //4.3 删除当前节点表记录
        await _nodeMainService.Delete(zbpm.nodid);

        if ("end" != nextNode.facty)
        {
            //5.1 当前节点表保存下一个待审批节点
            BpmNodeMain nodeMain = await _nodeMainService.SaveNode(zbpm, nextNode);
            nextNode.nodid = nodeMain.id;
            //5.2 历史节点表保存下一个待审批节点
            await _nodeHistService.SaveNode(nodeMain);

            //6.1 当前任务表创建待审节点的任务
            List<BpmTaskMain> mainTaskList = await _taskMainService.CreateTaskList(zbpm, nextNode);
            //6.2 历史任务表创建待审节点的任务
            await _taskHistService.CreateTaskList(mainTaskList);

            //7.1 删除之前的待办
            await _todoService.DoneTodos(zbpm);
            //7.2 发起新待办
            await _todoService.SendTodos(zbpm, mainTaskList);
            
            //8 将流程更新成完结
            bpmProcMain.state = "20";
            await repo.Context.Updateable(bpmProcMain)
                .UpdateColumns(it => new {it.state}).ExecuteCommandAsync();
        }
        else
        {
            //5 历史节点表保存结束节点
            string endNodeId = await _nodeHistService.SaveEndNode(zbpm);

            //6 评审表保存结束节点的评审信息
            await _auditMainService.SaveEndAudit(zbpm, endNodeId);

            //7 删除之前的待办
            await _todoService.DoneTodos(zbpm);

            //8 将流程更新成完结
            bpmProcMain.state = "30";
            await repo.Context.Updateable(bpmProcMain)
                .UpdateColumns(it => new {it.state}).ExecuteCommandAsync();
        }

        return nextNode;
    }

    //驳回流程
    public async Task<Znode> HandlerRefuse(Zbpm zbpm)
    {
        zbpm.haman = XuserUtil.getUserId();
        string sql = "select m.id as \"proid\",m.name \"prona\" from bpm_proc_main m where m.id=@proid";
        dynamic map = repo.Context.Ado.SqlQuerySingle<dynamic>(sql, new {proid = zbpm.proid});
        zbpm.prona = "" + map.prona;

        //驳回: "起草节点"（返回本人）
        if (zbpm.retag)
        {
            zbpm.opinf = "驳回: " + zbpm.tarno + "." + zbpm.tarna + "（返回本人）";
        }
        else
        {
            zbpm.opinf = "驳回: " + zbpm.tarno + "." + zbpm.tarna;
        }

        //1 评审表保存当前节点的评审信息
        await _auditMainService.SaveAudit(zbpm);

        //2.1 将历史任务变成已办
        BpmTaskHist histTask = await _taskHistService.FindOne(zbpm.tasid);
        histTask.haman = zbpm.haman;
        histTask.entim = DateTime.Now;
        histTask.state = "30";
        await _taskHistService.Update(histTask);
        //2.2 删除当前任务表记录
        await _taskMainService.DeleteAllByProid(zbpm.proid);
        //2.3 删除历史任务未结束记录
        await _taskHistService.DeleteAllByProidNotEnd(zbpm.proid);


        //3 创建驳回节点
//        Znode refuseNode = hand.getNodeInfo(zbpm,zbpm.getTarno());
        Znode refuseNode = new Znode();
        refuseNode.facno = zbpm.tarno;
        refuseNode.facna = zbpm.tarna;
        refuseNode.exmen = zbpm.exman;
        refuseNode.facty = "review";

        //4.1 将历史节点变成已办
        BpmNodeHist histNode = await _nodeHistService.FindOne(zbpm.nodid);
        histNode.tarno = zbpm.tarno;
        histNode.tarna = zbpm.tarna;
        histNode.entim = DateTime.Now;
        histNode.state = "30";
        await _nodeHistService.Update(histNode);
        //4.2 删除当前节点表记录
        await _nodeMainService.Delete(zbpm.nodid);

        //5.1 当前节点表保存下一个待审批节点
        BpmNodeMain nodeMain = await _nodeMainService.SaveNode(zbpm, refuseNode);
        refuseNode.nodid = nodeMain.id;
        //5.2 历史节点表保存下一个待审批节点
        await _nodeHistService.SaveNode(nodeMain);
        //5.3 如果驳回时勾选了 驳回的节点通过后直接返回本节点
        if (zbpm.retag)
        {
            BpmProcParam param = new BpmProcParam();
            param.id = YitIdHelper.NextId() + "";
            param.proid = zbpm.proid;
            param.offty = "proc";
            param.offid = zbpm.proid;
            param.pakey = zbpm.tarno + "#refuse";
            param.paval = zbpm.facno;
            _paramService.Save(param);
        }

        //6.1 当前任务表创建待审节点的任务
        List<BpmTaskMain> mainTaskList = await _taskMainService.CreateTaskList(zbpm, refuseNode);
        //6.2 历史任务表创建待审节点的任务
        await _taskHistService.CreateTaskList(mainTaskList);

        //7.1 删除之前的待办
        await _todoService.DoneTodos(zbpm);
        //7.2 发起新待办
        await _todoService.SendTodos(zbpm, mainTaskList);
        return refuseNode;
    }
    
     //转办流程
    public async Task handlerTurn(Zbpm zbpm) {
        zbpm.haman=XuserUtil.getUserId();

        string sql = "select m.id \"proid\",m.name \"prona\" from bpm_proc_main m where m.id=@id";
        dynamic map = repo.Context.Ado.SqlQuerySingle<dynamic>(sql, new {id = zbpm.proid});
        zbpm.prona="" + map.prona;
        
        string turnManSql = "select id,name,type from sys_org where id=@id";
        SysOrg sysOrg= await repo.Context.Ado.SqlQuerySingleAsync<SysOrg>(turnManSql,new {id=zbpm.tumid});
        if(zbpm.tutag){
            zbpm.opinf="转办: "+sysOrg.name+"（完整转办）";
        }else{
            zbpm.opinf="转办: "+sysOrg.name;
        }
        //1 评审表保存当前节点的评审信息
        await _auditMainService.SaveAudit(zbpm);

        BpmTaskMain task = await _taskMainService.FindOne(zbpm.tasid);
        task.exman=zbpm.tumid;
        await _taskMainService.Update(task);

       await _todoService.DoneTodo(zbpm);
       await _todoService.SendTodo(zbpm,zbpm.tumid);

    }

    //沟通流程
    public async Task handlerCommunicate(Zbpm zbpm) {
        var dbOptions = App.GetOptions<ConnectionStringsOptions>();
        zbpm.haman=XuserUtil.getUserId();

        string sql = "select m.id \"proid\",m.name \"prona\" from bpm_proc_main m where m.id=@id";
        dynamic map = repo.Context.Ado.SqlQuerySingle<dynamic>(sql, new {id = zbpm.proid});
        zbpm.prona="" + map.prona;

        string ids = "'" + zbpm.coids.Replace(";", "','") + "'";
        string sql2 = "select t.id,t.name,t.type from sys_org t where id in ("+ids+")";
        if (dbOptions.ConnectionConfigs[0].DbType == DbType.MySql)
        {
            sql2 += " order by field(id,"+ids+")";
        }else if (dbOptions.ConnectionConfigs[0].DbType == DbType.SqlServer)
        {
            sql2+=" order by CHARINDEX(id,'" + ids.Replace("'","") + "')";
        }else if (dbOptions.ConnectionConfigs[0].DbType == DbType.Oracle)
        {
            sql2+=" order by INSTR('" + ids.Replace("'","") + "',id)";
        }
        List<SysOrg> list= await repo.Context.Ado.SqlQueryAsync<SysOrg>(sql2);
        
        String names="";
        foreach (var sysOrg in list)
        {
            names += sysOrg.name + ";";
        }
        names = names.Substring(0, names.Length - 1);
        if(zbpm.cotag){
            zbpm.opinf="沟通: "+names+"（隐藏意见）";
        }else{
            zbpm.opinf="沟通: "+names;
        }
        //1 评审表保存当前节点的评审信息
        await _auditMainService.SaveAudit(zbpm);

        Znode currNode = new Znode(zbpm.facna);
        currNode.nodid=zbpm.nodid;
        currNode.facno=zbpm.facno;
        currNode.facty="communicate";
        currNode.exmen=zbpm.coids;
        currNode.flway="3";

        //6.1 当前任务表创建待审节点的任务
        List<BpmTaskMain> mainTaskList =await _taskMainService.CreateTaskList(zbpm, currNode);
        //6.2 历史任务表创建待审节点的任务
        await _taskHistService.CreateTaskList(mainTaskList);
        //7.2 发起新待办
        await _todoService.SendTodos(zbpm, mainTaskList);

    }

    //沟通回复
    public async Task handlerBacommunicate(Zbpm zbpm) {
        zbpm.haman=XuserUtil.getUserId();

        zbpm.opinf="沟通回复";
        //1 评审表保存当前节点的评审信息
        await _auditMainService.SaveAudit(zbpm);

        //2.1 将历史任务变成已办
        BpmTaskHist histTask = await _taskHistService.FindOne(zbpm.tasid);
        histTask.haman=zbpm.haman;
        histTask.entim=DateTime.Now;
        histTask.state="30";
        //2.2 删除当前任务表记录
        await _taskMainService.Delete(zbpm.tasid);

        await _todoService.DoneTodo(zbpm);

//        Znode currNode = new Znode(zbpm.getFacno());
//        currNode.setNodid(zbpm.getNodid());
//        currNode.setFacno(zbpm.getFacno());
//        currNode.setFacty("communicate");
//        currNode.setExmen(zbpm.getCoids());
//        currNode.setFlway("3");
//
//        //6.1 当前任务表创建待审节点的任务
//        List<BpmTaskMain> mainTaskList = taskMainService.createTaskList(zbpm, currNode);
//        //6.2 历史任务表创建待审节点的任务
//        taskHistService.createTaskList(mainTaskList);
//        //7.2 发起新待办
//        todoService.sendTodos(zbpm, mainTaskList);

    }

    //废弃流程
    public async Task handlerAbandon(Zbpm zbpm) {
        zbpm.haman=XuserUtil.getUserId();
//        string sql = "select m.id as proid,m.name as prona from bpm_proc_main m where m.id=?";
//        Map<String, Object> map = jdbcDao.findMap(sql, zbpm.getProid());
//        zbpm.setProna("" + map.get("prona"));

        zbpm.opinf="废弃";
        //1 评审表保存当前节点的评审信息
        await _auditMainService.SaveAudit(zbpm);
        //2.1 将历史任务变成已办
        BpmTaskHist histTask = await _taskHistService.FindOne(zbpm.tasid);
        histTask.haman=zbpm.haman;
        histTask.entim=DateTime.Now;;
        histTask.state="30";
        //2.2 删除当前任务表记录
        await _taskMainService.DeleteAllByProid(zbpm.proid);
        //2.3 删除历史任务未结束记录
        await _taskHistService.DeleteAllByProidNotEnd(zbpm.proid);

        //4.1 将历史节点变成已办
        BpmNodeHist histNode =await _nodeHistService.FindOne(zbpm.nodid);
        histNode.tarno=zbpm.tarno;
        histNode.tarna=zbpm.tarna;
        histNode.entim=DateTime.Now;
        histNode.state="30";
        //4.2 删除当前节点表记录
        await _nodeMainService.Delete(zbpm.nodid);

        //7.1 删除之前的待办
        await _todoService.DoneTodos(zbpm);
    }
    
    
    private async Task exmenTran(Znode znode) {
        var dbOptions = App.GetOptions<ConnectionStringsOptions>();
        string tamen = "";
        if (!string.IsNullOrEmpty(znode.exmen) && !znode.exmen.Contains(";")) {
            string tamenSql = "select t.id, t.name,t.type from sys_org t where t.id=@id";
            SysOrg sysOrg= await repo.Context.Ado.SqlQuerySingleAsync<SysOrg>(tamenSql,new {id=znode.exmen});
            if (sysOrg.type==32) {
                SysOrg org = await _sysOrgRoleTreeService.calc(XuserUtil.getUserId(), sysOrg.id);
                tamen = org.id;
            } else {
                tamen = sysOrg.id;
            }
        } else if (!string.IsNullOrEmpty(znode.exmen) && znode.exmen.Contains(";")) {
            string ids = "'" + znode.exmen.Replace(";", "','") + "'";
            
            string sql = "select t.id,t.name,t.type from sys_org t where id in "+"("+ids+")";
            if (dbOptions.ConnectionConfigs[0].DbType == DbType.MySql)
            {
                sql += " order by field(id," + ids + ")";
            }else if (dbOptions.ConnectionConfigs[0].DbType == DbType.SqlServer)
            {
                sql+=" order by CHARINDEX(id,'" + ids.Replace("'","") + "')";
            }else if (dbOptions.ConnectionConfigs[0].DbType == DbType.Oracle)
            {
                sql+=" order by INSTR('" + ids.Replace("'","") + "',id)";
            }
            List<SysOrg> list= await repo.Context.Ado.SqlQueryAsync<SysOrg>(sql);
            foreach (var sysOrg in list)
            {
                if (sysOrg.type == 32) {
                    SysOrg org =await _sysOrgRoleTreeService.calc(XuserUtil.getUserId(), sysOrg.id);
                    tamen += org.id + ";";
                } else {
                    tamen += sysOrg.id + ";";
                }
            }
            tamen = tamen.Substring(0, tamen.Length - 1);
        }
        znode.exmen=tamen;
    }

    private readonly SysOrgRoleTreeService _sysOrgRoleTreeService;

    private readonly BpmNodeHistService _nodeHistService;

    private readonly BpmNodeMainService _nodeMainService;

    private readonly BpmAuditMainService _auditMainService;

    private readonly BpmTaskHistService _taskHistService;

    private readonly BpmTaskMainService _taskMainService;

    private readonly SysTodoMainService _todoService;

    private readonly BpmProcParamService _paramService;

    private readonly BpmProcMainHand _hand;


    public BpmProcMainService(SqlSugarRepository<BpmProcMain> repo,
        BpmProcMainHand hand,
        BpmNodeHistService nodeHistService,
        BpmNodeMainService nodeMainService,
        BpmAuditMainService auditMainService,
        BpmTaskHistService taskHistService,
        BpmTaskMainService taskMainService,
        SysTodoMainService todoService,
        BpmProcParamService paramService,
        SysOrgRoleTreeService sysOrgRoleTreeService)
    {
        this.repo = repo;
        _hand = hand;
        _nodeHistService = nodeHistService;
        _nodeMainService = nodeMainService;
        _auditMainService = auditMainService;
        _taskHistService = taskHistService;
        _taskMainService = taskMainService;
        _todoService = todoService;
        _paramService = paramService;
        _sysOrgRoleTreeService = sysOrgRoleTreeService;
    }
}